// ServerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Server.h"
#include "ServerDlg.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CServerDlg::IDD, pParent)
	, m_msgString(_T(""))
	, max_Socket(0)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	//  m_nsocket = 0;
	m_szNhap = 0;
}

void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_BOXCHAT, m_msgString);

	char buff[100];
	sprintf(buff, "%d", max_Socket);
	CString w;
	w += buff;
	DDX_Text(pDX, IDC_NSOCKET, w);
	DDX_Text(pDX, IDC_NSOCKET, m_szNhap);
	DDV_MinMaxInt(pDX, m_szNhap, 1, 5);
	DDX_Control(pDX, IDC_NSOCKET, m_editNhap);
}

BEGIN_MESSAGE_MAP(CServerDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_MESSAGE(WM_SOCKET,SockMsg)
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_LISTEN, &CServerDlg::OnBnClickedListen)
	ON_BN_CLICKED(IDC_CANCEL, &CServerDlg::OnBnClickedCancel)
	ON_EN_CHANGE(IDC_NSOCKET, &CServerDlg::OnEnChangeNsocket)
	ON_BN_CLICKED(IDC_CANCEL2, &CServerDlg::OnBnClickedCancel2)
END_MESSAGE_MAP()

BOOL CServerDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here

	max_Socket = 1;
	game_started = false;

	srand((unsigned)time(NULL));
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CServerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CServerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CServerDlg::Split(CString src,CString des[2])
{
	int p1,p2;

	p1=src.Find(_T("\r\n"),0);
	des[0]=src.Mid(0,p1);

	p2=src.Find(_T("\r\n"),p1+1);
	des[1]=src.Mid(p1+2,p2-(p1+2));

}

char* CServerDlg::ConvertToChar(const CString &s)
{
	int nSize = s.GetLength();
	char *pAnsiString = new char[nSize+1];
	memset(pAnsiString,0,nSize+1);
	wcstombs(pAnsiString, s, nSize+1);
	return pAnsiString;
}

void CServerDlg::mSend(SOCKET sk, CString Command)
{
	int Len=Command.GetLength();
	Len+=Len;
	PBYTE sendBuff = new BYTE[1000];
	memset(sendBuff,0,1000);
	memcpy(sendBuff,(PBYTE)(LPCTSTR)Command, Len);
	send(sk,(char*)&Len,sizeof(Len),0);
	send(sk,(char*)sendBuff,Len,0);
	delete sendBuff;
}

int CServerDlg::mRecv(SOCKET sk, CString &Command)
{
	PBYTE buffer = new BYTE[1000];
	memset(buffer,0, 1000);
	recv(sk ,(char*)&buffLength,sizeof(int),0);
	recv(sk,(char*)buffer,buffLength,0);
	TCHAR* ttc = (TCHAR*)buffer;
	Command = ttc;

	if(Command.GetLength()==0)
		return -1;
	return 0;

}

void CServerDlg::OnBnClickedListen()
{
	// TODO: Add your control notification handler code here
	CString buff;
	m_editNhap.GetWindowText(buff);
	_stscanf(buff, _T("%d"), &max_Socket);
#if PRODUCTIN
	if (max_Socket < 4 || max_Socket > 8)
#endif
	if (max_Socket == 0)
	{
		MessageBox(_T("Only in [4;8]"));
		return;
	}
	
	if (game_started == false)
	{
		sockServer =socket(AF_INET,SOCK_STREAM,0);
		serverAdd.sin_family=AF_INET;
		serverAdd.sin_port=htons(PORT);
		serverAdd.sin_addr.s_addr =htonl(INADDR_ANY);
		bind(sockServer,(SOCKADDR*)&serverAdd,sizeof (serverAdd));
		listen(sockServer,5);
		int err =WSAAsyncSelect(sockServer,m_hWnd,WM_SOCKET,FD_READ|FD_ACCEPT|FD_CLOSE);
		if (err)
			MessageBox((LPCTSTR)"Cant call WSAAsyncSelect");
	}
	GetDlgItem(IDC_LISTEN)->EnableWindow(FALSE);
	number_Socket=0;
	game_round = 0;
	game_started = false;
	allow_connect = true;
	check_in = 0;

	pSock=new SockName[200]; /*** FIXME ***/

}

void CServerDlg::OnBnClickedCancel()
{
	;
}

LRESULT CServerDlg::SockMsg(WPARAM wParam, LPARAM lParam)
{
	if (WSAGETSELECTERROR(lParam))
	{
		closesocket(wParam);
	}
	switch(WSAGETSELECTEVENT(lParam))
	{
	case FD_ACCEPT:
		{
			pSock[number_Socket].sockClient = accept(wParam,NULL,NULL);
			GetDlgItem(IDC_LISTEN)->EnableWindow(FALSE);
			break;
		}
	case FD_READ:
		{

			int post = -1, dpos = -1;

			for(int i=0;i<number_Socket;i++)
			{
				if(pSock[i].sockClient==wParam)
				{
					if (i<number_Socket)
						post=i;
				}
			}

			CString temp;
			if(mRecv(wParam, temp) < 0)
				break;
			Split(temp,strResult);
			int flag =_ttoi(strResult[0]);
			char* tem = ConvertToChar(strResult[1]);
			switch(flag)
			{
			case 1://Login
				{
#ifdef DEBUG_NV
goto not_allowed;
#endif
					if (!allow_connect) { goto not_allowed; }
					int t = 0;
					if(number_Socket>0)
					{
						for(int i=0;i<number_Socket;i++)
						{
							if(strcmp(tem,pSock[i].Name)==0)//Trung ten user
							{
								t=1;
								break;
							}
						}
					}

					if(t==0)
					{
						strcpy(pSock[number_Socket].Name,tem);
						Command=_T("1\r\nWelcome to Bingo 0.1\r\n");
						m_msgString+=_T("New player: ") + strResult[1] + _T("\r\n");
						number_Socket++;
						// thi is for the dang nhap thanh cong
						mSend(wParam,Command);
						/* Message to all the socket new player join*/
						if (number_Socket != max_Socket) 
						{
							for (int i = 0; i < number_Socket; i++)
							{
								char buff[100];
								sprintf(buff, "2\r\n%d/%d connected\r\n", number_Socket, max_Socket);	
								Command = buff;
								mSend(pSock[i].sockClient, Command);
							}
						}
						else
						{
							for (int i = 0; i < number_Socket; i++) {
								Command = _T("3\r\nSubmit your number now folks :-)\r\n");
								mSend(pSock[i].sockClient, Command);
							}
						}
					}
					else
					{
not_allowed:
						if (!allow_connect)
							Command = _T("1\r\n3\r\n");
						else

							Command = _T("1\r\n4\r\n");
						mSend(wParam,Command);
					}
					UpdateData(FALSE);
					break;
				}

			case 2: // he submit his number
				{
					int post = -1;
					for(int i=0;i<number_Socket;i++)
					{
						if(pSock[i].sockClient==wParam)
						{
							if (i<number_Socket)
								post=i;
						}
					}
					if (1) {
						m_msgString+=pSock[post].Name ;
						m_msgString+=" submitted his number ";
						m_msgString+= tem; // tem should be CString ?
						m_msgString+="\r\n";
						pSock[post].nb = atoi(tem);

						if (pSock[post].nb < 1 || pSock[post].nb > 10)
						{
							Command = _T("3\r\nI can only handle number in range [1;10] :-)\r\n");
							mSend(pSock[post].sockClient, Command);
							break;
						}

						if (++check_in < number_Socket)
						{
								Command = _T("2\r\nWaiting for other submitting their number\r\n");
								mSend(pSock[post].sockClient, Command);
						}

						if (check_in >= number_Socket) bingo_result();
					}

					UpdateData(FALSE);

					break;
				}

			case 3:
				{	
					int post = -1;
					for(int i=0;i<number_Socket;i++)
					{
						if(pSock[i].sockClient==wParam)
						{
							if (i<number_Socket)
								post=i;
						}
					}


					m_msgString+=pSock[post].Name;
					m_msgString+=" disconnected\r\n";
					closesocket(wParam);
					for(int j = post; j < number_Socket;j++)
					{
						pSock[post].sockClient = pSock[post+1].sockClient;
						strcpy(	pSock[post].Name,pSock[post+1].Name);				
					}
					number_Socket--;

					UpdateData(FALSE);
					break;
				}
			}
			break;
		}

	case FD_CLOSE:
		{
			///UpdateData();
			int post = -1;
			for(int i=0;i<number_Socket;i++)
			{
				if(pSock[i].sockClient==wParam)
				{
					if (i<number_Socket)
						post=i;
				}
			}

			m_msgString+=pSock[post].Name;
			m_msgString+=" logout\r\n";
			closesocket(wParam);
			for(int j = post; j < number_Socket;j++)
			{
				pSock[post].sockClient = pSock[post+1].sockClient;
				strcpy(	pSock[post].Name,pSock[post+1].Name);				
			}
			number_Socket--;
			if (number_Socket == 0)
			{
				GetDlgItem(IDC_LISTEN)->EnableWindow(TRUE);
				allow_connect = false;
			}
			UpdateData(FALSE);
			break;
		}

	}
	return 0;
}

int random_in_range (unsigned int min, unsigned int max)
{
  int base_random = rand(); /* in [0, RAND_MAX] */
  if (RAND_MAX == base_random) return random_in_range(min, max);
  /* now guaranteed to be in [0, RAND_MAX) */
  int range       = max - min,
      remainder   = RAND_MAX % range,
      bucket      = RAND_MAX / range;
  /* There are range buckets, plus one smaller interval
     within remainder of RAND_MAX */
  if (base_random < RAND_MAX - remainder) {
    return min + base_random/bucket;
  } else {
    return random_in_range (min, max);
  }
}

void CServerDlg::bingo_result ()
{
	if (!game_started)
	{
		game_started = true;
		for (int i = 0; i < number_Socket; i++)
		{

			pSock[i].ps = rand() % (30 - 10 + 1) + 10;
			char buff[100];
			sprintf(buff, "2\r\nYour initialial point: %d\r\n", pSock[i].ps);	
			Command = buff;
			mSend(pSock[i].sockClient, Command);
#ifdef DEBUG_0
			pSock[i].ps = 0;
#endif
		}
	}
	
	R = random_in_range(1, 10);

	for (int i = 0; i < number_Socket; i++)
	{
		pSock[i].ps -= 2;
		pSock[i].next_game = true;
		if (pSock[i].ps <= 0)
		{
			pSock[i].next_game = false;
		}
		if (pSock[i].nb == R)
		{ 
			pSock[i].ps += pSock[i].nb * 5;
		}

		if (pSock[i].next_game == true)
		{
			char buff[100];
			sprintf(buff, "2\r\nGame: %d/5 Server: %d - You %d - Your Score %d\r\n", game_round + 1, R, pSock[i].nb, pSock[i].ps);	
			Command = buff;
			mSend(pSock[i].sockClient, Command);
		}
		else
		{
			char buff[100];
			sprintf(buff, "2\r\nYou have Lost ! Total: %d\r\n", pSock[i].ps);	
			Command = buff;
			mSend(pSock[i].sockClient, Command);
		}
		pSock[i].nb = -1;
	}
	game_round++;
	if (game_round < 5)
	{
		for (int i = 0; i < number_Socket; i++)
		{
			if (pSock[i].ps > 0)
				Command = "5\r\nSubmit another number folks :-)\r\n";
			else
				Command = _T("4\r\nGame ended\r\n");
			mSend(pSock[i].sockClient, Command);
		}
		check_in = 0;
	}
	else
		for (int i = 0; i < number_Socket; i++)
		{
			char buff[100];
			sprintf(buff, "2\r\n%s Total Score %d\r\n", pSock[i].Name, pSock[i].ps);
			Command = buff;
			mSend(pSock[i].sockClient, Command);
			Command = "4\r\n\r\n";
			mSend(pSock[i].sockClient, Command);
		}
}

void CServerDlg::OnEnChangeNsocket()
{
	CString buff;
	m_editNhap.GetWindowText(buff);
	_stscanf(buff, _T("%d"), &max_Socket);
}


void CServerDlg::OnBnClickedCancel2()
{
	OnCancel();
}